day 4-1¶
このノートブックの実行例はこちら(HTML版)で確認できます
0. はじめに¶
ページ上部のメニューバーにある Kernel メニューをクリックし、プルダウンメニューから [Change Kernel ...] を選び、gssm2024:Python を選択してください。
ノートブック上部の右隅に表示されたカーネル名が gssm2024:Python になっていることを確認してください。
1. テキスト分析 (1)¶
1.0 事前準備 (定義済み関数の読み込み)¶
以下のセルを修正せずに実行してください
import warnings
warnings.simplefilter('ignore')
import gssm_utils
%matplotlib inline
1.1 データのダウンロード (前回ダウンロード済みのためスキップ)¶
以下のデータがダウンロード済みです
| ファイル名 | 件数 | データセット | 備考 |
|---|---|---|---|
| rakuten-1000-2023-2024.xlsx.zip | 10,000 | •レジャー+ビジネスの 10エリア •エリアごと 1,000件 (ランダムサンプリング) •期間: 2023/1~2024 GW明け |
本講義の全体を通して使用する |
# もし、再度ダウンロードが必要な場合は残りの行のコメントマーク「#」を除去して、このセルを再実行してください
# FILE_ID = "1EeCuDrfKdlsMxG9p3Ot7TIxfV9_f2smY"
# !gdown --id {FILE_ID}
# !unzip -o rakuten-1000-2023-2024.xlsx.zip
1.2 データの読み込み (DataFrame型)¶
import numpy as np
import pandas as pd
all_df = pd.read_excel("rakuten-1000-2023-2024.xlsx")
print(all_df.shape)
display(all_df.head())
(10000, 18)
| カテゴリー | エリア | 施設番号 | 施設名 | コメント | 総合 | サービス | 立地 | 部屋 | 設備・アメニティ | 風呂 | 食事 | 旅行の目的 | 同伴者 | 宿泊年月 | 投稿者 | 年代 | 性別 | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | A_レジャー | 01_登別 | 80732 | 登別カルルス温泉 湯元オロフレ荘 | 彼のリクエストでカルルス温泉に宿泊させていただきました。北海道ラブ割利用でお得に宿泊できる分... | 5 | 5 | 4 | 5 | 5.0 | 5.0 | 5.0 | レジャー | 恋人 | 45231 | 投稿者 | na | na |
| 1 | A_レジャー | 01_登別 | 149334 | 天然温泉 幸鐘の湯 ドーミーイン東室蘭(ドーミーイン・御宿野乃 ホテルズグループ) | 室蘭方面の旅行の時には何度か宿泊しています。ドーミーインのサービスはとても良くて大好きです。... | 4 | 5 | 5 | 2 | 5.0 | 5.0 | 5.0 | レジャー | 家族 | 45413 | 投稿者 | na | na |
| 2 | A_レジャー | 01_登別 | 109022 | 心のリゾート 海の別邸ふる川 | もう一度行きたくなる宿でした。部屋もワンランクアップしていただき感謝しています。お風呂も最高... | 4 | 3 | 5 | 5 | 4.0 | 5.0 | 3.0 | レジャー | 一人 | 45261 | gaku0713 | 60代 | 男性 |
| 3 | A_レジャー | 01_登別 | 7506 | ホテルニューバジェット室蘭 | 居心地良く過ごせました | 4 | 4 | 4 | 4 | 4.0 | 4.0 | 3.0 | レジャー | 一人 | 45200 | 投稿者 | na | na |
| 4 | A_レジャー | 01_登別 | 37380 | 登別温泉 旅亭 花ゆら | 事前カード精算で露天風呂付特別和洋室を予約しましたが別の和室に案内されました。すぐ違うことに... | 1 | 2 | 4 | 2 | 2.0 | 4.0 | 3.0 | レジャー | 家族 | 45323 | 投稿者 | na | na |
1.3 単語の抽出¶
コメント列から単語を抽出する (単語を品詞「名詞」「形容詞」「未知語」で絞り込む)
# 必要ライブラリのインポート
from collections import defaultdict
import MeCab
# mecab の初期化
tagger = MeCab.Tagger("-r ../tools/usr/local/etc/mecabrc --unk-feature 未知語")
# 単語頻度辞書の初期化
word_counts = defaultdict(lambda: 0)
# 抽出語情報リストの初期化
words = []
# 半角->全角変換マクロを定義する
ZEN = "".join(chr(0xff01 + i) for i in range(94))
HAN = "".join(chr(0x21 + i) for i in range(94))
HAN2ZEN = str.maketrans(HAN, ZEN)
# ストップワードを定義する
# stopwords = ['する', 'ある', 'ない', 'いう', 'もの', 'こと', 'よう', 'なる', 'ほう']
stopwords = ["湯畑"]
# データ1行ごとのループ
for index, row in all_df.iterrows():
# 半角->全角変換した後で, mecab で解析する
node = tagger.parseToNode(row["コメント"].translate(HAN2ZEN))
# 形態素ごとのループ
while node:
# 解析結果を要素ごとにバラす
features = node.feature.split(',')
# 品詞1 を取り出す
pos1 = features[0]
# 品詞2 を取り出す
pos2 = features[1] if len(features) > 1 else ""
# 原形 を取り出す
base = features[6] if len(features) > 6 else None
# 原型がストップワードに含まれない単語のみ抽出する
if base not in stopwords:
# 「名詞-一般」
if (pos1 == "名詞" and pos2 == "一般"):
base = base if base is not None else node.surface
postag = "名詞"
key = (base, postag)
# 単語頻度辞書をカウントアップする
word_counts[key] += 1
# 抽出語情報をリストに追加する
words.append([index + 1, base, postag, row["カテゴリー"], row["エリア"], key])
# 「形容動詞」
elif (pos1 == "名詞" and pos2 == "形容動詞語幹"):
base = base if base is not None else node.surface
base = f"{base}だ"
postag = "形容動詞"
key = (base, postag)
# 単語頻度辞書をカウントアップする
word_counts[key] += 1
# 抽出語情報をリストに追加する
words.append([index + 1, base, postag, row["カテゴリー"], row["エリア"], key])
# 「形容詞」
elif pos1 == "形容詞":
base = base if base is not None else node.surface
postag = "形容詞"
key = (base, postag)
# 単語頻度辞書をカウントアップする
word_counts[key] += 1
# 抽出語情報をリストに追加する
words.append([index + 1, base, postag, row["カテゴリー"], row["エリア"], key])
# 「未知語」
elif pos1 == "未知語":
base = base if base is not None else node.surface
postag = "未知語"
key = (base, postag)
# 単語頻度辞書をカウントアップする
word_counts[key] += 1
# 抽出語情報をリストに追加する
words.append([index + 1, base, postag, row["カテゴリー"], row["エリア"], key])
# 次の形態素へ
node = node.next
# DataFrme 型に整える
columns = [
"文書ID",
# "単語ID",
"表層",
"品詞",
"カテゴリー",
"エリア",
"dict_key",
]
docs_df = pd.DataFrame(words, columns=columns)
# DataFrame を表示する
print(docs_df.shape)
display(docs_df.head())
(158822, 6)
| 文書ID | 表層 | 品詞 | カテゴリー | エリア | dict_key | |
|---|---|---|---|---|---|---|
| 0 | 1 | リクエスト | 名詞 | A_レジャー | 01_登別 | (リクエスト, 名詞) |
| 1 | 1 | 温泉 | 名詞 | A_レジャー | 01_登別 | (温泉, 名詞) |
| 2 | 1 | ラブ | 名詞 | A_レジャー | 01_登別 | (ラブ, 名詞) |
| 3 | 1 | 割 | 名詞 | A_レジャー | 01_登別 | (割, 名詞) |
| 4 | 1 | 得 | 名詞 | A_レジャー | 01_登別 | (得, 名詞) |
1.4 単語の出現回数 (Top 75)¶
単語の出現回数をカウントする
# 「文書-抽出語」 表から単語の出現回数をカウントする
word_list = []
for i, (k, v) in enumerate(sorted(word_counts.items(), key=lambda x:x[1], reverse=True)):
word_list.append((i, k[0], v, k))
# DataFrame 型に整える
columns = [
"単語ID",
"表層",
"出現頻度",
"dict_key"
]
word_counts_df = pd.DataFrame(word_list, columns=columns)
# DataFrame を表示する
print(word_counts_df.shape)
display(word_counts_df.head(10))
(9060, 4)
| 単語ID | 表層 | 出現頻度 | dict_key | |
|---|---|---|---|---|
| 0 | 0 | 部屋 | 6768 | (部屋, 名詞) |
| 1 | 1 | 良い | 5397 | (良い, 形容詞) |
| 2 | 2 | ホテル | 3001 | (ホテル, 名詞) |
| 3 | 3 | 風呂 | 2692 | (風呂, 名詞) |
| 4 | 4 | ない | 2392 | (ない, 形容詞) |
| 5 | 5 | 美味しい | 2294 | (美味しい, 形容詞) |
| 6 | 6 | 温泉 | 1854 | (温泉, 名詞) |
| 7 | 7 | スタッフ | 1677 | (スタッフ, 名詞) |
| 8 | 8 | 立地 | 1532 | (立地, 名詞) |
| 9 | 9 | よい | 1517 | (よい, 形容詞) |
単語IDを紐つける (出現回数 Top 150語のみ抽出する)
# 「単語出現回数」 表から出現回数Top 150語のみ抽出する
word_counts_150_df = word_counts_df[0:150]
# 「文書-抽出語」 表も出現回数Top 150語のみに絞り込む
merged_df = pd.merge(docs_df, word_counts_150_df, how="inner", on="dict_key", suffixes=["", "_right"])
docs_150_df = merged_df[["文書ID", "単語ID", "表層", "品詞", "カテゴリー", "エリア", "dict_key"]]
# DataFrame を表示する
print(docs_150_df.shape)
display(docs_150_df)
(87334, 7)
| 文書ID | 単語ID | 表層 | 品詞 | カテゴリー | エリア | dict_key | |
|---|---|---|---|---|---|---|---|
| 0 | 1 | 6 | 温泉 | 名詞 | A_レジャー | 01_登別 | (温泉, 名詞) |
| 1 | 1 | 0 | 部屋 | 名詞 | A_レジャー | 01_登別 | (部屋, 名詞) |
| 2 | 1 | 66 | プラン | 名詞 | A_レジャー | 01_登別 | (プラン, 名詞) |
| 3 | 1 | 15 | 大変だ | 形容動詞 | A_レジャー | 01_登別 | (大変だ, 形容動詞) |
| 4 | 1 | 6 | 温泉 | 名詞 | A_レジャー | 01_登別 | (温泉, 名詞) |
| ... | ... | ... | ... | ... | ... | ... | ... |
| 87329 | 10000 | 6 | 温泉 | 名詞 | B_ビジネス | 10_福岡 | (温泉, 名詞) |
| 87330 | 10000 | 6 | 温泉 | 名詞 | B_ビジネス | 10_福岡 | (温泉, 名詞) |
| 87331 | 10000 | 33 | コンビニ | 名詞 | B_ビジネス | 10_福岡 | (コンビニ, 名詞) |
| 87332 | 10000 | 2 | ホテル | 名詞 | B_ビジネス | 10_福岡 | (ホテル, 名詞) |
| 87333 | 10000 | 1 | 良い | 形容詞 | B_ビジネス | 10_福岡 | (良い, 形容詞) |
87334 rows × 7 columns
1.5 ワードクラウド¶
# 出現回数Top 75単語でワードクラウドを作成する
words = ' '.join(word_counts_df['表層'][0:75])
gssm_utils.plot_wordcloud(words)
1.6 「文書-抽出語」表の作成¶
「文書-抽出語」表を作成する (出現回数 Top 75語)
# 「単語出現回数」 表から出現回数Top 75語のみ抽出する
word_counts_75_df = word_counts_df[0:75]
# 「文書-抽出語」 表も出現回数Top 75語のみに絞り込む
merged_df = pd.merge(docs_df, word_counts_75_df, how="inner", on="dict_key", suffixes=["", "_right"])
docs_75_df = merged_df[["文書ID", "単語ID", "表層", "品詞", "カテゴリー", "エリア", "dict_key"]]
# 「カテゴリー,エリア」でクロス集計する
cross_75_df = pd.crosstab(
[
docs_75_df['カテゴリー'],
docs_75_df['エリア'],
docs_75_df['文書ID']
],
docs_75_df['単語ID'], margins=False
)
cross_75_df.columns = word_counts_75_df["表層"]
# DataFrame を表示する
print(cross_75_df.shape)
display(cross_75_df)
(9677, 75)
| 表層 | 部屋 | 良い | ホテル | 風呂 | ない | 美味しい | 温泉 | スタッフ | 立地 | よい | ... | 徒歩 | プラン | 少ない | 安い | 旅館 | ありがたい | 楽しい | 建物 | 必要だ | 十分だ | ||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| カテゴリー | エリア | 文書ID | |||||||||||||||||||||
| A_レジャー | 01_登別 | 1 | 1 | 0 | 0 | 0 | 0 | 1 | 5 | 1 | 0 | 0 | ... | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 2 | 4 | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ||
| 3 | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ||
| 4 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ||
| 5 | 5 | 0 | 0 | 1 | 2 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ||
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| B_ビジネス | 10_福岡 | 9996 | 2 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 9997 | 1 | 0 | 0 | 2 | 0 | 0 | 0 | 0 | 1 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ||
| 9998 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ||
| 9999 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ||
| 10000 | 0 | 1 | 1 | 0 | 0 | 0 | 2 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
9677 rows × 75 columns
「文書-抽出語」 表を {0,1} に変換する
# 「文書-抽出語」 表を {0,1} に変換する
cross_75_df[cross_75_df > 0] = 1
# DataFrame を表示する
print(cross_75_df.shape)
display(cross_75_df)
(9677, 75)
| 表層 | 部屋 | 良い | ホテル | 風呂 | ない | 美味しい | 温泉 | スタッフ | 立地 | よい | ... | 徒歩 | プラン | 少ない | 安い | 旅館 | ありがたい | 楽しい | 建物 | 必要だ | 十分だ | ||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| カテゴリー | エリア | 文書ID | |||||||||||||||||||||
| A_レジャー | 01_登別 | 1 | 1 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 0 | 0 | ... | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 2 | 1 | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ||
| 3 | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ||
| 4 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ||
| 5 | 1 | 0 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ||
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| B_ビジネス | 10_福岡 | 9996 | 1 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 9997 | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 1 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ||
| 9998 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ||
| 9999 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ||
| 10000 | 0 | 1 | 1 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
9677 rows × 75 columns
1.7 共起ネットワーク図¶
1.7.1 共起度行列を作成する (抽出語-抽出語)¶
# 必要ライブラリのインポート
from scipy.sparse import csc_matrix
# 共起行列を作成する
X = cross_75_df.values
X = csc_matrix(X)
Xc = (X.T * X)
# 対角成分のみにする
Xc = np.triu(Xc.toarray())
# DataFrame 型に整える
cooccur_75_df = pd.DataFrame(Xc, columns=cross_75_df.columns, index=cross_75_df.columns)
# DataFrame を表示する
print(cooccur_75_df.shape)
display(cooccur_75_df.head())
(75, 75)
| 表層 | 部屋 | 良い | ホテル | 風呂 | ない | 美味しい | 温泉 | スタッフ | 立地 | よい | ... | 徒歩 | プラン | 少ない | 安い | 旅館 | ありがたい | 楽しい | 建物 | 必要だ | 十分だ |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 表層 | |||||||||||||||||||||
| 部屋 | 4580 | 2023 | 1165 | 1313 | 1094 | 1112 | 769 | 791 | 780 | 714 | ... | 192 | 207 | 209 | 179 | 148 | 200 | 153 | 184 | 180 | 191 |
| 良い | 0 | 3839 | 922 | 1044 | 764 | 919 | 696 | 745 | 790 | 344 | ... | 169 | 146 | 156 | 140 | 134 | 135 | 130 | 152 | 122 | 126 |
| ホテル | 0 | 0 | 2157 | 435 | 550 | 395 | 270 | 373 | 426 | 298 | ... | 124 | 88 | 87 | 100 | 34 | 95 | 64 | 89 | 103 | 84 |
| 風呂 | 0 | 0 | 0 | 2150 | 521 | 612 | 411 | 362 | 303 | 348 | ... | 84 | 84 | 113 | 65 | 88 | 86 | 85 | 80 | 82 | 86 |
| ない | 0 | 0 | 0 | 0 | 1746 | 392 | 321 | 344 | 303 | 326 | ... | 91 | 110 | 118 | 96 | 70 | 83 | 46 | 78 | 118 | 77 |
5 rows × 75 columns
1.7.2 Jaccard 係数を求める (抽出語-抽出語)¶
# 共起行列の中身を Jaccard 係数に入れ替える
jaccard_75_df = gssm_utils.jaccard_coef(cooccur_75_df, cross_75_df)
# DataFrame を表示する
print(jaccard_75_df.shape)
display(jaccard_75_df.head())
(75, 75)
| 表層 | 部屋 | 良い | ホテル | 風呂 | ない | 美味しい | 温泉 | スタッフ | 立地 | よい | ... | 徒歩 | プラン | 少ない | 安い | 旅館 | ありがたい | 楽しい | 建物 | 必要だ | 十分だ |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 表層 | |||||||||||||||||||||
| 部屋 | 0.0 | 0.316291 | 0.209081 | 0.242385 | 0.209098 | 0.202329 | 0.147488 | 0.151823 | 0.147448 | 0.139426 | ... | 0.040695 | 0.044174 | 0.044468 | 0.037892 | 0.031637 | 0.042553 | 0.032347 | 0.039132 | 0.038322 | 0.040917 |
| 良い | 0.0 | 0.000000 | 0.181711 | 0.211122 | 0.158473 | 0.185732 | 0.153102 | 0.165006 | 0.174047 | 0.072421 | ... | 0.042250 | 0.036445 | 0.038883 | 0.034809 | 0.033915 | 0.033549 | 0.032403 | 0.038067 | 0.030394 | 0.031563 |
| ホテル | 0.0 | 0.000000 | 0.000000 | 0.112345 | 0.164032 | 0.104222 | 0.082067 | 0.116381 | 0.132257 | 0.095697 | ... | 0.052476 | 0.036944 | 0.036265 | 0.042017 | 0.014352 | 0.039882 | 0.026711 | 0.037489 | 0.043811 | 0.035714 |
| 風呂 | 0.0 | 0.000000 | 0.000000 | 0.000000 | 0.154370 | 0.171621 | 0.130808 | 0.112808 | 0.090800 | 0.113837 | ... | 0.035058 | 0.035309 | 0.047760 | 0.026993 | 0.038128 | 0.036074 | 0.035895 | 0.033670 | 0.034672 | 0.036705 |
| ない | 0.0 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.115908 | 0.113508 | 0.121856 | 0.103307 | 0.121869 | ... | 0.045844 | 0.056439 | 0.060296 | 0.048657 | 0.036420 | 0.041856 | 0.022966 | 0.039514 | 0.061299 | 0.039528 |
5 rows × 75 columns
1.7.3 プロットする¶
# 抽出語の出現回数(ノードの大きさ)を取得する
word_counts = cross_75_df.sum(axis=0).values
# 共起行列(Jaccard係数)で共起ネットワーク図を作成する
gssm_utils.plot_cooccur_network(jaccard_75_df, word_counts, np.sort(jaccard_75_df.values.reshape(-1))[::-1][60])
<Figure size 800x800 with 0 Axes>
1.8 係り受けネットワーク図¶
1.8.1 係り受け行列を作成する¶
# チャンク(文節)から単語を取り出す
def get_words(tree, from_chunk, stopwords):
# チャンク(文節)の開始位置を取得する
beg = from_chunk.token_pos
# チャンクの開始位置を取得する
end = from_chunk.token_pos + from_chunk.token_size
# 抽出語情報リストの初期化
words = []
# チャンク(文節)ごとのループ
for i in range(beg, end):
# チャンク中の形態素を取り出す
token = tree.token(i)
# 解析結果を要素ごとにバラす
features = token.feature.split(',')
# 品詞1 を取り出す
pos1 = features[0]
# 品詞2 を取り出す
pos2 = features[1] if len(features) > 1 else ""
# 原形 を取り出す
base = features[6] if len(features) > 6 else None
# 原型がストップワードに含まれない単語のみ抽出する
if base not in stopwords:
# 「名詞-一般」
if (pos1 == "名詞" and pos2 == "一般"):
base = base if base is not None else node.surface
postag = "名詞"
key = (base, postag)
# 抽出語情報をリストに追加する
words.append(key)
# 「形容動詞」
elif (pos1 == "名詞" and pos2 == "形容動詞語幹"):
base = base if base is not None else node.surface
base = f"{base}だ"
postag = "形容動詞"
key = (base, postag)
# 抽出語情報をリストに追加する
words.append(key)
# 「形容詞」
elif pos1 == "形容詞":
base = base if base is not None else node.surface
postag = "形容詞"
key = (base, postag)
# 抽出語情報をリストに追加する
words.append(key)
# 「未知語」
elif pos1 == "未知語":
base = base if base is not None else node.surface
postag = "未知語"
key = (base, postag)
# 抽出語情報をリストに追加する
words.append(key)
# 抽出語情報をリストを返却する
return words
# 必要ライブラリのインポート
import CaboCha
# cabocha の初期化
cp = CaboCha.Parser("-r ../tools/usr/local/etc/cabocharc")
# 半角->全角変換マクロを定義する
ZEN = "".join(chr(0xff01 + i) for i in range(94))
HAN = "".join(chr(0x21 + i) for i in range(94))
HAN2ZEN = str.maketrans(HAN, ZEN)
# ストップワードを定義する
# stopwords = ['する', 'ある', 'ない', 'いう', 'もの', 'こと', 'よう', 'なる', 'ほう']
stopwords = ['*'] # 原形に 「'*'」 が出力された場合に除去するため
# 係り受けペア辞書の初期化
pair_counts = defaultdict(lambda: 0)
pairs = []
# データ1行ごとのループ
for index, row in all_df.iterrows():
# 半角->全角変換した後で, cabocha で解析する
tree = cp.parse(row["コメント"].translate(HAN2ZEN))
# 解析結果から空でないチャンク(文節)のリストを集める
chunks = {}
key = 0
for i in range(tree.size()):
tok = tree.token(i)
if tok.chunk:
chunks[key] = tok.chunk
key += 1
# 係り元と係り先の単語情報(原形と品詞)を集める
for from_chunk in chunks.values():
# 係り先がなければスキップ
if from_chunk.link < 0:
continue
# 係り先のチャンク(文節)を取得する
to_chunk = chunks[from_chunk.link]
# 係り元の単語情報(原形と品詞)を取得する
from_words = get_words(tree, from_chunk, stopwords)
# 係り先の単語情報(原形と品詞)を取得する
to_words = get_words(tree, to_chunk, stopwords)
# 係り受けペアと頻度を収集する
for f in from_words:
for t in to_words:
key = (f[0], t[0])
pair_counts[key] += 1
# 係り受け行列を初期化する (共起行列と同じ形)
Xd = np.zeros(cooccur_75_df.shape)
# 係り受けペアを係り受け列に変換する
for (f,t), v in pair_counts.items():
columns = list(cooccur_75_df.columns)
if f in columns and t in columns:
i = columns.index(f)
j = columns.index(t)
Xd[i,j] = v
# DataFrme 型に整える
dep_75_df = pd.DataFrame(Xd, columns=cooccur_75_df.columns, index=cooccur_75_df.columns)
print(dep_75_df.shape)
display(dep_75_df.head())
(75, 75)
| 表層 | 部屋 | 良い | ホテル | 風呂 | ない | 美味しい | 温泉 | スタッフ | 立地 | よい | ... | 徒歩 | プラン | 少ない | 安い | 旅館 | ありがたい | 楽しい | 建物 | 必要だ | 十分だ |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 表層 | |||||||||||||||||||||
| 部屋 | 0.0 | 8.0 | 0.0 | 1.0 | 1.0 | 1.0 | 0.0 | 0.0 | 0.0 | 3.0 | ... | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
| 良い | 3.0 | 2.0 | 24.0 | 0.0 | 3.0 | 2.0 | 1.0 | 0.0 | 1.0 | 0.0 | ... | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
| ホテル | 0.0 | 7.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | ... | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
| 風呂 | 0.0 | 12.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 4.0 | ... | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 |
| ない | 1.0 | 3.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | ... | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
5 rows × 75 columns
1.8.2 条件付き確率を求める¶
# 係り受け行列の中身(numpy行列)を取り出す
Xc = dep_75_df.values
# 係り受け行列(条件付き確率)を初期化する (元の係り受け行列と同じ形)
Xd = np.zeros(Xc.shape)
# 係り元単語の出現頻度を取得する
word_counts = cooccur_75_df.sum(axis=0).values
# 係り受けペアごとのループ
for (f,t), v in pair_counts.items():
columns = list(dep_75_df.columns)
# 係り元と係り先の両方が列に含まれる
if f in columns and t in columns:
i = columns.index(f)
j = columns.index(t)
# 条件付き確率(係り受け頻度/係り先出現回数)を求める
Xd[i,j] = v / word_counts[i]
# DataFrame 型に整える
dep_75_df = pd.DataFrame(Xd, columns=dep_75_df.columns, index=dep_75_df.columns)
# DataFrame を表示する
print(dep_75_df.shape)
display(dep_75_df.head())
(75, 75)
| 表層 | 部屋 | 良い | ホテル | 風呂 | ない | 美味しい | 温泉 | スタッフ | 立地 | よい | ... | 徒歩 | プラン | 少ない | 安い | 旅館 | ありがたい | 楽しい | 建物 | 必要だ | 十分だ |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 表層 | |||||||||||||||||||||
| 部屋 | 0.000000 | 0.001747 | 0.000000 | 0.000218 | 0.000218 | 0.000218 | 0.000000 | 0.0 | 0.000000 | 0.000655 | ... | 0.0 | 0.0 | 0.0 | 0.0 | 0.000000 | 0.0 | 0.0 | 0.0 | 0.000000 | 0.0 |
| 良い | 0.000512 | 0.000341 | 0.004094 | 0.000000 | 0.000512 | 0.000341 | 0.000171 | 0.0 | 0.000171 | 0.000000 | ... | 0.0 | 0.0 | 0.0 | 0.0 | 0.000171 | 0.0 | 0.0 | 0.0 | 0.000000 | 0.0 |
| ホテル | 0.000000 | 0.001649 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.0 | 0.000000 | 0.000236 | ... | 0.0 | 0.0 | 0.0 | 0.0 | 0.000000 | 0.0 | 0.0 | 0.0 | 0.000000 | 0.0 |
| 風呂 | 0.000000 | 0.002428 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.0 | 0.000000 | 0.000809 | ... | 0.0 | 0.0 | 0.0 | 0.0 | 0.000000 | 0.0 | 0.0 | 0.0 | 0.000202 | 0.0 |
| ない | 0.000214 | 0.000642 | 0.000214 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.0 | 0.000000 | 0.000214 | ... | 0.0 | 0.0 | 0.0 | 0.0 | 0.000000 | 0.0 | 0.0 | 0.0 | 0.000000 | 0.0 |
5 rows × 75 columns
1.8.3 プロットする¶
# 抽出語の出現回数(ノードの大きさ)を取得する
word_counts = cross_75_df.sum(axis=0).values
# 係り受け(条件付き確率)で共起ネットワーク図を作成する
gssm_utils.plot_dependency_network(dep_75_df, word_counts, np.sort(dep_75_df.values.reshape(-1))[::-1][60], pyvis=True)
pyvis.html
<Figure size 800x800 with 0 Axes>
1.9 対応分析¶
「文書-抽出語」 表を確認する
# DataFrame を表示する
print(cross_75_df.shape)
display(cross_75_df.head())
(9677, 75)
| 表層 | 部屋 | 良い | ホテル | 風呂 | ない | 美味しい | 温泉 | スタッフ | 立地 | よい | ... | 徒歩 | プラン | 少ない | 安い | 旅館 | ありがたい | 楽しい | 建物 | 必要だ | 十分だ | ||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| カテゴリー | エリア | 文書ID | |||||||||||||||||||||
| A_レジャー | 01_登別 | 1 | 1 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 0 | 0 | ... | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 2 | 1 | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ||
| 3 | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ||
| 4 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ||
| 5 | 1 | 0 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
5 rows × 75 columns
1.9.1 「外部変数-抽出語」 クロス集計表を作成する¶
# 「カテゴリー」のクロス集計と「エリア」のクロス集計を連結する
aggregate_75_df = pd.concat(
[
cross_75_df.groupby(level='カテゴリー').sum(),
cross_75_df.groupby(level='エリア').sum()
]
)
# DataFrame を表示する
print(aggregate_75_df.shape)
display(aggregate_75_df)
(12, 75)
| 表層 | 部屋 | 良い | ホテル | 風呂 | ない | 美味しい | 温泉 | スタッフ | 立地 | よい | ... | 徒歩 | プラン | 少ない | 安い | 旅館 | ありがたい | 楽しい | 建物 | 必要だ | 十分だ |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| A_レジャー | 2367 | 2134 | 789 | 1498 | 957 | 1486 | 1290 | 916 | 548 | 677 | ... | 135 | 168 | 207 | 128 | 236 | 144 | 234 | 204 | 104 | 138 |
| B_ビジネス | 2213 | 1705 | 1368 | 652 | 789 | 542 | 113 | 505 | 942 | 578 | ... | 195 | 145 | 122 | 195 | 10 | 176 | 69 | 102 | 193 | 141 |
| 01_登別 | 433 | 422 | 173 | 296 | 193 | 260 | 271 | 149 | 47 | 111 | ... | 12 | 40 | 45 | 26 | 30 | 23 | 40 | 27 | 16 | 24 |
| 02_草津 | 489 | 468 | 161 | 376 | 198 | 305 | 311 | 177 | 146 | 134 | ... | 39 | 41 | 36 | 31 | 54 | 30 | 60 | 61 | 20 | 28 |
| 03_箱根 | 544 | 454 | 158 | 331 | 199 | 373 | 234 | 222 | 69 | 156 | ... | 30 | 37 | 55 | 23 | 59 | 27 | 49 | 42 | 33 | 32 |
| 04_道後 | 408 | 380 | 228 | 190 | 157 | 177 | 231 | 130 | 184 | 135 | ... | 31 | 24 | 38 | 31 | 20 | 33 | 29 | 31 | 16 | 24 |
| 05_湯布院 | 493 | 410 | 69 | 305 | 210 | 371 | 243 | 238 | 102 | 141 | ... | 23 | 26 | 33 | 17 | 73 | 31 | 56 | 43 | 19 | 30 |
| 06_札幌 | 461 | 359 | 278 | 126 | 138 | 135 | 24 | 95 | 191 | 92 | ... | 29 | 34 | 23 | 35 | 1 | 34 | 21 | 19 | 38 | 24 |
| 07_名古屋 | 430 | 337 | 267 | 123 | 155 | 104 | 30 | 99 | 164 | 130 | ... | 40 | 32 | 29 | 41 | 3 | 42 | 9 | 31 | 29 | 32 |
| 08_東京 | 398 | 345 | 276 | 119 | 162 | 82 | 9 | 100 | 172 | 113 | ... | 31 | 31 | 28 | 29 | 3 | 30 | 10 | 12 | 38 | 30 |
| 09_大阪 | 459 | 316 | 262 | 139 | 151 | 100 | 25 | 104 | 184 | 122 | ... | 27 | 25 | 17 | 45 | 2 | 32 | 14 | 18 | 37 | 28 |
| 10_福岡 | 465 | 348 | 285 | 145 | 183 | 121 | 25 | 107 | 231 | 121 | ... | 68 | 23 | 25 | 45 | 1 | 38 | 15 | 22 | 51 | 27 |
12 rows × 75 columns
1.9.2 対応分析プロットを作成する¶
# 必要ライブラリのインポート
import mca
# ライブラリ mca による対応分析
ncols = aggregate_75_df.shape[1]
mca_ben = mca.MCA(aggregate_75_df, ncols=ncols, benzecri=False)
# 行方向および列方向の値を取り出す
row_coord = mca_ben.fs_r(N=2)
col_coord = mca_ben.fs_c(N=2)
# 固有値を求める
eigenvalues = mca_ben.L
total = np.sum(eigenvalues)
# 寄与率を求める
explained_inertia = 100 * eigenvalues / total
# 行方向および列方向のラベルを取得する
row_labels = aggregate_75_df.index
col_labels = aggregate_75_df.columns
# プロットする
gssm_utils.plot_coresp(row_coord, col_coord, row_labels, col_labels, explained_inertia)
1.10 トピックモデル¶
「文書-抽出語」 表を確認する
# DataFrame を表示する
print(cross_75_df.shape)
display(cross_75_df.head())
(9677, 75)
| 表層 | 部屋 | 良い | ホテル | 風呂 | ない | 美味しい | 温泉 | スタッフ | 立地 | よい | ... | 徒歩 | プラン | 少ない | 安い | 旅館 | ありがたい | 楽しい | 建物 | 必要だ | 十分だ | ||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| カテゴリー | エリア | 文書ID | |||||||||||||||||||||
| A_レジャー | 01_登別 | 1 | 1 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 0 | 0 | ... | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 2 | 1 | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ||
| 3 | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ||
| 4 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ||
| 5 | 1 | 0 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
5 rows × 75 columns
1.10.1 トピックを抽出する (LDA)¶
# 必要ライブラリのインポート
from sklearn.decomposition import LatentDirichletAllocation as LDA
# ライブラリ LDA によるトピック抽出
lda = LDA(max_iter=25, learning_method='batch', random_state=42, n_jobs=-1, n_components=6)
lda.fit(cross_75_df.values)
# トピックごとに出現確率Top 20語を表示する
n_top_words = 20
feature_names = cross_75_df.columns
for topic_idx, topic in enumerate(lda.components_):
print(f"Topic # {topic_idx+1}:", end=" ")
for i in topic.argsort()[:-n_top_words-1:-1]:
print(feature_names[i], end=" ")
print()
Topic # 1: 部屋 良い 綺麗だ 風呂 立地 狭い 広い 浴場 トイレ 無い 残念だ ない 気 人 十分だ 美味しい 安い 快適だ 値段 悪い Topic # 2: ホテル フロント ない 部屋 いい 良い 古い 感じ アウト スタッフ よい 荷物 立地 他 残念だ 値段 必要だ 建物 気 悪い Topic # 3: 部屋 ホテル 快適だ 多い 清潔だ 広い ベッド 良い 嬉しい 種類 美味しい ない アメニティ バイキング バス 風呂 浴場 少ない 無料 プラン Topic # 4: 温泉 最高 部屋 良い 風呂 美味しい 露天風呂 夕食 宿 ない 残念だ お湯 湯 多い よい 浴場 いい 広い 感じ 旅館 Topic # 5: 便利だ 駅 近い コンビニ 立地 部屋 良い よい ホテル きれいだ 徒歩 静かだ 場所 やすい バス 大変だ 快適だ 広い 非常だ 清潔だ Topic # 6: スタッフ 美味しい 大変だ 良い 家族 部屋 素晴らしい 風呂 気持ちよい 宿 丁寧だ 温泉 素敵だ 親切だ ご飯 楽しい 子供 よい おいしい 機会
ChatGPT を使ってトピックを説明する
プロンプトの例:
以下はトピックとトピックごとの高確率ワードです. これを読んで各トピックの要約を日本語で作成してください.
Topic # 1 フロント ホテル 浴場 部屋 親切だ 良い …
結果の例:
- トピック1: ホテルのスタッフと設備
- トピック2: ホテルの立地と利便性
- トピック3: 温泉と食事の質
- トピック4: スタッフの対応と設備の質
- トピック5: 部屋の質と価格
- トピック6: 部屋の広さと快適さ
1.10.2 トピックをワードクラウドで描画する¶
# トピックごとに出現確率Top 75語でワードクラウドを作成する
n_top_words = 75
gssm_utils.plot_topic_model(lda, feature_names, n_top_words)
1.10.3 トピック分布をプロットする¶
# 文書ごとのトピック比率を取得
doc_topic_distributions = lda.transform(cross_75_df.values)
# 文書全体のトピック比率を計算(平均を取る)
overall_topic_distribution = np.mean(doc_topic_distributions, axis=0)
gssm_utils.plot_topic_distribution(overall_topic_distribution)
1.11 外部変数の利用¶
1.11.1 「文書-抽出語」表の作成¶
「文書-抽出語」表を作成する (出現回数 Top 150語)
# 「単語出現回数」 表から出現回数Top 150語のみ抽出する
word_counts_150_df = word_counts_df[0:150]
# 「文書-抽出語」 表も出現回数Top 150語のみに絞り込む
merged_df = pd.merge(docs_df, word_counts_150_df, how="inner", on="dict_key", suffixes=["", "_right"])
docs_150_df = merged_df[["文書ID", "単語ID", "表層", "品詞", "カテゴリー", "エリア", "dict_key"]]
# 「カテゴリー,エリア」でクロス集計する
cross_150_df = pd.crosstab(
[
docs_150_df['カテゴリー'],
docs_150_df['エリア'],
docs_150_df['文書ID']
],
docs_150_df['単語ID'], margins=False
)
cross_150_df.columns = word_counts_150_df["表層"]
# DataFrame を表示する
print(cross_150_df.shape)
display(cross_150_df)
(9782, 150)
| 表層 | 部屋 | 良い | ホテル | 風呂 | ない | 美味しい | 温泉 | スタッフ | 立地 | よい | ... | キレイだ | スペース | 笑顔 | 小さい | 次 | 布団 | 冷蔵庫 | リピート | 楽しみ | 周り | ||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| カテゴリー | エリア | 文書ID | |||||||||||||||||||||
| A_レジャー | 01_登別 | 1 | 1 | 0 | 0 | 0 | 0 | 1 | 5 | 1 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 2 | 4 | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ||
| 3 | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ||
| 4 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ||
| 5 | 5 | 0 | 0 | 1 | 2 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ||
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| B_ビジネス | 10_福岡 | 9996 | 2 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
| 9997 | 1 | 0 | 0 | 2 | 0 | 0 | 0 | 0 | 1 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ||
| 9998 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ||
| 9999 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ||
| 10000 | 0 | 1 | 1 | 0 | 0 | 0 | 2 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
9782 rows × 150 columns
「文書-抽出語」表を {0,1} に変換する
# 「文書-抽出語」 表を {0,1} に変換する
cross_150_df[cross_150_df > 0] = 1
# DataFrame を表示する
print(cross_150_df.shape)
display(cross_150_df)
(9782, 150)
| 表層 | 部屋 | 良い | ホテル | 風呂 | ない | 美味しい | 温泉 | スタッフ | 立地 | よい | ... | キレイだ | スペース | 笑顔 | 小さい | 次 | 布団 | 冷蔵庫 | リピート | 楽しみ | 周り | ||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| カテゴリー | エリア | 文書ID | |||||||||||||||||||||
| A_レジャー | 01_登別 | 1 | 1 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 2 | 1 | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ||
| 3 | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ||
| 4 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ||
| 5 | 1 | 0 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ||
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| B_ビジネス | 10_福岡 | 9996 | 1 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
| 9997 | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 1 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ||
| 9998 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ||
| 9999 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ||
| 10000 | 0 | 1 | 1 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
9782 rows × 150 columns
1.11.2 共起行列を作成する (外部変数-抽出語)¶
# 「カテゴリー」のクロス集計と「エリア」のクロス集計を連結する
aggregate_df = pd.concat(
[
cross_150_df.groupby(level='カテゴリー').sum(),
cross_150_df.groupby(level='エリア').sum()
]
)
# DataFrame を表示する
print(aggregate_df.shape)
display(aggregate_df)
(12, 150)
| 表層 | 部屋 | 良い | ホテル | 風呂 | ない | 美味しい | 温泉 | スタッフ | 立地 | よい | ... | キレイだ | スペース | 笑顔 | 小さい | 次 | 布団 | 冷蔵庫 | リピート | 楽しみ | 周り |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| A_レジャー | 2367 | 2134 | 789 | 1498 | 957 | 1486 | 1290 | 916 | 548 | 677 | ... | 63 | 61 | 127 | 102 | 91 | 115 | 81 | 105 | 121 | 74 |
| B_ビジネス | 2213 | 1705 | 1368 | 652 | 789 | 542 | 113 | 505 | 942 | 578 | ... | 120 | 105 | 48 | 67 | 85 | 35 | 87 | 69 | 48 | 97 |
| 01_登別 | 433 | 422 | 173 | 296 | 193 | 260 | 271 | 149 | 47 | 111 | ... | 8 | 15 | 19 | 21 | 14 | 28 | 18 | 14 | 35 | 12 |
| 02_草津 | 489 | 468 | 161 | 376 | 198 | 305 | 311 | 177 | 146 | 134 | ... | 13 | 8 | 18 | 15 | 27 | 31 | 16 | 26 | 24 | 6 |
| 03_箱根 | 544 | 454 | 158 | 331 | 199 | 373 | 234 | 222 | 69 | 156 | ... | 17 | 16 | 24 | 36 | 15 | 30 | 16 | 29 | 27 | 13 |
| 04_道後 | 408 | 380 | 228 | 190 | 157 | 177 | 231 | 130 | 184 | 135 | ... | 19 | 14 | 22 | 21 | 13 | 11 | 9 | 9 | 11 | 8 |
| 05_湯布院 | 493 | 410 | 69 | 305 | 210 | 371 | 243 | 238 | 102 | 141 | ... | 6 | 8 | 44 | 9 | 22 | 15 | 22 | 27 | 24 | 35 |
| 06_札幌 | 461 | 359 | 278 | 126 | 138 | 135 | 24 | 95 | 191 | 92 | ... | 27 | 24 | 10 | 11 | 18 | 3 | 13 | 11 | 13 | 17 |
| 07_名古屋 | 430 | 337 | 267 | 123 | 155 | 104 | 30 | 99 | 164 | 130 | ... | 33 | 24 | 14 | 19 | 14 | 5 | 15 | 15 | 6 | 16 |
| 08_東京 | 398 | 345 | 276 | 119 | 162 | 82 | 9 | 100 | 172 | 113 | ... | 14 | 18 | 7 | 14 | 17 | 12 | 19 | 17 | 7 | 18 |
| 09_大阪 | 459 | 316 | 262 | 139 | 151 | 100 | 25 | 104 | 184 | 122 | ... | 31 | 17 | 5 | 11 | 22 | 6 | 18 | 18 | 8 | 20 |
| 10_福岡 | 465 | 348 | 285 | 145 | 183 | 121 | 25 | 107 | 231 | 121 | ... | 15 | 22 | 12 | 12 | 14 | 9 | 22 | 8 | 14 | 26 |
12 rows × 150 columns
1.11.3 Jaccard 係数を求める (外部変数-抽出語)¶
# 抽出語の出現回数を取得する
word_counts = cross_150_df.sum(axis=0).values
# 属性(外部変数)出現数を取得する
attr_counts = np.hstack(
[
all_df.value_counts('カテゴリー').values,
all_df.value_counts('エリア').values
]
)
# 共起行列の中身を Jaccard 係数に入れ替える
jaccard_attrs_df = gssm_utils.jaccard_attrs_coef(aggregate_df, attr_counts, word_counts, total=10000, conditional=False)
# DataFrame を表示する
print(jaccard_attrs_df.shape)
display(jaccard_attrs_df)
(12, 150)
| 表層 | 部屋 | 良い | ホテル | 風呂 | ない | 美味しい | 温泉 | スタッフ | 立地 | よい | ... | キレイだ | スペース | 笑顔 | 小さい | 次 | 布団 | 冷蔵庫 | リピート | 楽しみ | 周り |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| A_レジャー | 0.328157 | 0.318270 | 0.000000 | 0.265039 | 0.165314 | 0.268134 | 0.252298 | 0.166394 | 0.000000 | 0.121370 | ... | 0.000000 | 0.000000 | 0.025158 | 0.020130 | 0.017896 | 0.022840 | 0.000000 | 0.020714 | 0.023970 | 0.000000 |
| B_ビジネス | 0.000000 | 0.000000 | 0.236310 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.169791 | 0.000000 | ... | 0.023701 | 0.020747 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.017123 | 0.000000 | 0.000000 | 0.019117 |
| 01_登別 | 0.000000 | 0.095540 | 0.000000 | 0.103714 | 0.075597 | 0.093931 | 0.127111 | 0.065581 | 0.000000 | 0.000000 | ... | 0.000000 | 0.000000 | 0.016436 | 0.018293 | 0.000000 | 0.024955 | 0.015652 | 0.000000 | 0.030864 | 0.000000 |
| 02_草津 | 0.096052 | 0.107069 | 0.000000 | 0.135544 | 0.077708 | 0.112009 | 0.148662 | 0.078877 | 0.000000 | 0.063178 | ... | 0.000000 | 0.000000 | 0.015557 | 0.000000 | 0.023499 | 0.027703 | 0.000000 | 0.022648 | 0.020961 | 0.000000 |
| 03_箱根 | 0.108022 | 0.103535 | 0.000000 | 0.117418 | 0.078131 | 0.140490 | 0.107884 | 0.100955 | 0.000000 | 0.074321 | ... | 0.000000 | 0.000000 | 0.020851 | 0.031774 | 0.000000 | 0.026786 | 0.000000 | 0.025328 | 0.023643 | 0.000000 |
| 04_道後 | 0.000000 | 0.000000 | 0.077842 | 0.000000 | 0.000000 | 0.000000 | 0.106354 | 0.000000 | 0.079792 | 0.063679 | ... | 0.016323 | 0.000000 | 0.019081 | 0.018293 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 |
| 05_湯布院 | 0.096914 | 0.092572 | 0.000000 | 0.107206 | 0.082808 | 0.139631 | 0.112500 | 0.109024 | 0.000000 | 0.066698 | ... | 0.000000 | 0.000000 | 0.038904 | 0.000000 | 0.019064 | 0.000000 | 0.019197 | 0.023540 | 0.020961 | 0.030810 |
| 06_札幌 | 0.090057 | 0.000000 | 0.096561 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.083080 | 0.000000 | ... | 0.023356 | 0.021016 | 0.000000 | 0.000000 | 0.015544 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 |
| 07_名古屋 | 0.000000 | 0.000000 | 0.092388 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.070507 | 0.061176 | ... | 0.028696 | 0.021016 | 0.000000 | 0.016522 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 |
| 08_東京 | 0.000000 | 0.000000 | 0.095800 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.074202 | 0.000000 | ... | 0.000000 | 0.015679 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.016536 | 0.000000 | 0.000000 | 0.015611 |
| 09_大阪 | 0.089631 | 0.000000 | 0.090501 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.079792 | 0.000000 | ... | 0.026910 | 0.014795 | 0.000000 | 0.000000 | 0.019064 | 0.000000 | 0.015652 | 0.015571 | 0.000000 | 0.017376 |
| 10_福岡 | 0.090909 | 0.000000 | 0.099234 | 0.000000 | 0.071401 | 0.000000 | 0.000000 | 0.000000 | 0.102258 | 0.000000 | ... | 0.000000 | 0.019231 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.019197 | 0.000000 | 0.000000 | 0.022707 |
12 rows × 150 columns
1.11.4 特徴語ランキング¶
# 「カテゴリ」や「エリア」ごとに Jaccard 係数のTop 10語を抽出する
df_list = []
for index, row in jaccard_attrs_df.iterrows():
df_list.append(row.iloc[np.argsort(row.values)[::-1][:10]].reset_index())
# 「カテゴリ」や「エリア」ごとの Jaccard 係数のTop 10 を横方向に連結した DetaFrame を作成する
ranking_df = pd.DataFrame(pd.concat(df_list, axis=1))
ranking_df.columns = np.array([c for pair in [[x,f"jaccard"] for x in jaccard_attrs_df.index] for c in pair], dtype='object')
# DataFrame を表示する
display(ranking_df)
| A_レジャー | jaccard | B_ビジネス | jaccard | 01_登別 | jaccard | 02_草津 | jaccard | 03_箱根 | jaccard | ... | 06_札幌 | jaccard | 07_名古屋 | jaccard | 08_東京 | jaccard | 09_大阪 | jaccard | 10_福岡 | jaccard | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 部屋 | 0.328157 | ホテル | 0.236310 | 温泉 | 0.127111 | 温泉 | 0.148662 | 美味しい | 0.140490 | ... | ホテル | 0.096561 | ホテル | 0.092388 | 駅 | 0.121037 | 駅 | 0.092697 | 立地 | 0.102258 |
| 1 | 良い | 0.318270 | 立地 | 0.169791 | 風呂 | 0.103714 | 風呂 | 0.135544 | 露天風呂 | 0.132890 | ... | 部屋 | 0.090057 | 駅 | 0.084774 | 便利だ | 0.097297 | ホテル | 0.090501 | ホテル | 0.099234 |
| 2 | 美味しい | 0.268134 | 駅 | 0.153921 | 良い | 0.095540 | 宿 | 0.117160 | 風呂 | 0.117418 | ... | 立地 | 0.083080 | 便利だ | 0.072372 | ホテル | 0.095800 | 部屋 | 0.089631 | 部屋 | 0.090909 |
| 3 | 風呂 | 0.265039 | 便利だ | 0.145952 | 美味しい | 0.093931 | 美味しい | 0.112009 | 部屋 | 0.108022 | ... | 浴場 | 0.074408 | 立地 | 0.070507 | コンビニ | 0.082481 | 便利だ | 0.083823 | 駅 | 0.085379 |
| 4 | 温泉 | 0.252298 | フロント | 0.115707 | バイキング | 0.084771 | 良い | 0.107069 | 温泉 | 0.107884 | ... | 便利だ | 0.071806 | 近い | 0.070175 | 近い | 0.080283 | 立地 | 0.079792 | 便利だ | 0.084402 |
| 5 | スタッフ | 0.166394 | 近い | 0.112383 | 夕食 | 0.084353 | 部屋 | 0.096052 | 宿 | 0.107331 | ... | 快適だ | 0.065593 | 快適だ | 0.069420 | 立地 | 0.074202 | フロント | 0.073434 | ない | 0.071401 |
| 6 | ない | 0.165314 | 綺麗だ | 0.104125 | 種類 | 0.078832 | 湯 | 0.094293 | 良い | 0.103535 | ... | 広い | 0.063860 | フロント | 0.066524 | フロント | 0.067669 | 近い | 0.073314 | 綺麗だ | 0.067352 |
| 7 | 宿 | 0.159968 | 快適だ | 0.095608 | ない | 0.075597 | 最高 | 0.084139 | スタッフ | 0.100955 | ... | 駅 | 0.061681 | よい | 0.061176 | アメニティ | 0.063199 | 綺麗だ | 0.063525 | フロント | 0.064810 |
| 8 | 露天風呂 | 0.132394 | コンビニ | 0.087794 | 最高 | 0.071951 | 夕食 | 0.081567 | 夕食 | 0.097068 | ... | フロント | 0.060832 | コンビニ | 0.060788 | 綺麗だ | 0.057026 | 快適だ | 0.060534 | 近い | 0.063953 |
| 9 | 夕食 | 0.124876 | アメニティ | 0.076083 | 残念だ | 0.071800 | スタッフ | 0.078877 | 残念だ | 0.078534 | ... | 近い | 0.056582 | 綺麗だ | 0.059184 | 快適だ | 0.056147 | コンビニ | 0.057961 | バス | 0.058943 |
10 rows × 24 columns
1.11.5 ワードクラウド (カテゴリーごと)¶
for name, group in cross_150_df.groupby(level='カテゴリー'):
print(name)
# 「カテゴリー」ごとに Jaccard 係数でソートする
sorted_columns = np.argsort(jaccard_attrs_df.loc[name].values)[::-1][:75]
# Jaccard 係数Top 75語をソートして抽出する
group_cross_df = group.iloc[:,sorted_columns]
# プロットする
gssm_utils.plot_wordcloud(" ".join(group_cross_df.columns))
A_レジャー
B_ビジネス
1.11.6 共起ネットワーク図 (カテゴリーごと)¶
# 必要ライブラリのインポート
from scipy.sparse import csc_matrix
for name, group in cross_150_df.groupby(level='カテゴリー'):
print(name)
# 「カテゴリー」ごとに Jaccard 係数でソートする
sorted_columns = np.argsort(jaccard_attrs_df.loc[name].values)[::-1][:75]
# Jaccard 係数Top 75語をソートして抽出する
group_cross_df = group.iloc[:,sorted_columns]
# 共起行列を作成する
X = group_cross_df.values
X = csc_matrix(X)
Xc = (X.T * X)
Xc = np.triu(Xc.toarray())
# 共起行列を DataFrame に整える
group_cooccur_df = pd.DataFrame(Xc, columns=group_cross_df.columns, index=group_cross_df.columns)
# 共起行列の中身を Jaccard 係数に入れ替える
group_jaccard_df = gssm_utils.jaccard_coef(group_cooccur_df, group_cross_df)
# 抽出語の出現回数を取得する
word_counts = group.sum(axis=0).values
# プロットする
gssm_utils.plot_cooccur_network(group_jaccard_df, word_counts, np.sort(group_jaccard_df.values.reshape(-1))[::-1][60])
A_レジャー
<Figure size 800x800 with 0 Axes>
B_ビジネス
<Figure size 800x800 with 0 Axes>
1.11.7 トピック分布 (カテゴリーごと)¶
1.11.7.1 文書全体からトピックを抽出する (LDA)¶
# 必要ライブラリのインポート
from sklearn.decomposition import LatentDirichletAllocation as LDA
# ライブラリ LDA によるトピック抽出
lda = LDA(max_iter=25, learning_method='batch', random_state=42, n_jobs=-1, n_components=6)
lda.fit(cross_150_df.values)
# トピックごとに出現確率Top 20語を表示する
n_top_words = 20
feature_names = cross_150_df.columns
for topic_idx, topic in enumerate(lda.components_):
print(f"Topic # {topic_idx+1}:", end=" ")
for i in topic.argsort()[:-n_top_words-1:-1]:
print(feature_names[i], end=" ")
print()
Topic # 1: 部屋 ない 良い 残念だ ホテル 風呂 気 無い フロント 悪い 狭い トイレ 人 ベッド 他 欲しい アメニティ 音 必要だ アウト Topic # 2: 多い 部屋 種類 バイキング 美味しい 良い ホテル ない プラン 浴場 快適だ 広い 豊富だ 客 ビュッフェ 高い 品数 メニュー 少ない 嬉しい Topic # 3: 部屋 便利だ 立地 駅 良い 近い ホテル コンビニ 快適だ よい 綺麗だ 広い やすい 徒歩 バス 大変だ 場所 清潔だ 静かだ きれいだ Topic # 4: よい 温泉 部屋 最高 風呂 いい 良い お湯 湯 立地 美味しい 感じ 露天風呂 宿 ない サウナ きれいだ 浴場 温度 残念だ Topic # 5: 美味しい 部屋 風呂 良い 宿 家族 大変だ 温泉 露天風呂 広い 夕食 素晴らしい ご飯 最高 素敵だ 子供 量 綺麗だ 気持ち良い 楽しい Topic # 6: スタッフ 丁寧だ 良い フロント 親切だ ホテル 方々 部屋 皆さん 気持ちよい 女性 笑顔 大変だ 素晴らしい 美味しい アウト 優しい 素敵だ 綺麗だ 満足だ
1.11.7.2 トピックをワードクラウドで描画する¶
# トピックごとに出現確率Top 75語でワードクラウドを作成する
n_top_words = 75
gssm_utils.plot_topic_model(lda, feature_names, n_top_words)
1.11.7.3 トピック分布をプロットする¶
for name, group in cross_150_df.groupby(level='カテゴリー'):
print(name)
# 文書ごとのトピック比率を取得
doc_topic_distributions = lda.transform(group.values)
# 文書全体のトピック比率を計算(平均を取る)
overall_topic_distribution = np.mean(doc_topic_distributions, axis=0)
gssm_utils.plot_topic_distribution(overall_topic_distribution)
A_レジャー
B_ビジネス
1.11.8 本文の参照 (カテゴリーごと)¶
「夕食」「残念」という単語が含まれている口コミを表示する
for name, group in all_df.groupby('カテゴリー'):
print(name)
search_index = group['コメント'].str.contains('夕食') & group['コメント'].str.contains('残念')
display(group[search_index])
A_レジャー
| カテゴリー | エリア | 施設番号 | 施設名 | コメント | 総合 | サービス | 立地 | 部屋 | 設備・アメニティ | 風呂 | 食事 | 旅行の目的 | 同伴者 | 宿泊年月 | 投稿者 | 年代 | 性別 | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 70 | A_レジャー | 01_登別 | 29995 | ゆとりろ洞爺湖 | 会席料理の宿を探していて見つけました。お料理大変おいしかったです。オールインクルーシブも気兼... | 4 | 3 | 4 | 5 | 4.0 | 4.0 | 4.0 | レジャー | 家族 | 45139 | 投稿者 | na | na |
| 155 | A_レジャー | 01_登別 | 5499 | 室蘭プリンスホテル | シンプルで静かで素敵なホテルでした。趣のある商店街の一角にあり、歩いてすぐのところにコンビニ... | 4 | 4 | 5 | 4 | 4.0 | NaN | 3.0 | レジャー | 家族 | 45200 | Rikappa☆ | 40代 | 女性 |
| 166 | A_レジャー | 01_登別 | 37379 | 登別温泉 名湯の宿 パークホテル雅亭 | 2週間後の宿泊 温泉地のホテルでなるべく価格を抑えて朝夕食事付き で探し、古いのかな、とおも... | 5 | 5 | 5 | 5 | 5.0 | 5.0 | 5.0 | レジャー | 家族 | 45200 | にゃんこのら | 50代 | 女性 |
| 218 | A_レジャー | 01_登別 | 29995 | ゆとりろ洞爺湖 | 愛犬と足の悪い姉と夫の3人と一匹で、伺いました。お部屋は、古い感じですが、和室で皆寛ぐ事が出... | 4 | 5 | 3 | 3 | 3.0 | 2.0 | 5.0 | レジャー | 家族 | 45231 | 投稿者 | na | na |
| 244 | A_レジャー | 01_登別 | 162792 | 虎杖浜温泉ホテル | お食事は夕食朝食ともに、素晴らしかったです。お部屋とお風呂にブラシがなく?と思って帰りに気が... | 4 | 4 | 4 | 2 | 3.0 | 3.0 | 5.0 | レジャー | 家族 | 44986 | 投稿者 | na | na |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 4844 | A_レジャー | 05_湯布院 | 145331 | 旅館 由布山 | 夕食はとても美味しくいただきました。内風呂もいつでも入れてとても良かったです。ただ、フロント... | 3 | 2 | 2 | 3 | 3.0 | 4.0 | 4.0 | レジャー | 家族 | 45383 | ふゆのいろ | 60代 | 女性 |
| 4860 | A_レジャー | 05_湯布院 | 76377 | 由布院温泉 朝霧のみえる宿 ゆふいん花由 | 3月14日に宿泊しました。お出迎えから部屋の説明が非常に良かったです。夕食が残念でした食材に... | 3 | 3 | 4 | 5 | 4.0 | 5.0 | 2.0 | レジャー | 家族 | 44986 | 投稿者 | na | na |
| 4885 | A_レジャー | 05_湯布院 | 76447 | 由布院温泉 由布の癒 友里 | 別府に2泊して、湯布院にも行ってみたくなって急遽当日予約しました。素泊まりで予約しましたが、... | 3 | 4 | 3 | 4 | 3.0 | 4.0 | 3.0 | レジャー | 家族 | 45108 | maimaifaith | 50代 | 女性 |
| 4919 | A_レジャー | 05_湯布院 | 41833 | 由布院温泉 山荘 四季庵 | 家族旅行で利用しました。露天風呂は、虫が浮いていたので置いてあった網で取り除いてから入りまし... | 4 | 4 | 4 | 4 | 4.0 | 4.0 | 4.0 | レジャー | 家族 | 45139 | ダック0509 | 50代 | 女性 |
| 4996 | A_レジャー | 05_湯布院 | 75289 | 由布院温泉 東匠庵 | こちらの宿はクチコミが良く、やっと予約が取れたのですが、期待はずれな部分が多くとても残念でし... | 2 | 2 | 3 | 2 | 3.0 | 4.0 | 4.0 | レジャー | 家族 | 45231 | jkv | 40代 | 女性 |
133 rows × 18 columns
B_ビジネス
| カテゴリー | エリア | 施設番号 | 施設名 | コメント | 総合 | サービス | 立地 | 部屋 | 設備・アメニティ | 風呂 | 食事 | 旅行の目的 | 同伴者 | 宿泊年月 | 投稿者 | 年代 | 性別 | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 5570 | B_ビジネス | 06_札幌 | 163 | ニューオータニイン札幌 | 夕食の北海御前4500円付のプランにしましたが、とても値段に見合わない質、量の食事でした。そ... | 3 | 4 | 4 | 4 | 3.0 | 3.0 | 3.0 | ビジネス | 仕事仲間 | 45231 | 投稿者 | na | na |
| 5838 | B_ビジネス | 06_札幌 | 183892 | ダイワロイネットホテル札幌中島公園 | 娘の結婚式に出席するために親族含めて2泊しました。式場にも近く夕食を摂るため近くに美味しいお... | 4 | 5 | 5 | 5 | 5.0 | 5.0 | 3.0 | レジャー | 家族 | 45170 | ひきはち | 50代 | 女性 |
| 5972 | B_ビジネス | 06_札幌 | 17678 | シャトレーゼ ガトーキングダムサッポロ ホテル&スパリゾート | 良かった点駅前から乗車できるシャトルバスはとても便利でした、もう少し本数増やしてくれると観光... | 4 | 3 | 4 | 4 | 2.0 | 2.0 | 5.0 | レジャー | 家族 | 45323 | nanatama_go | 50代 | 男性 |
| 6417 | B_ビジネス | 07_名古屋 | 10897 | ホテル メルパルク名古屋 | 館内レストランで夕食を休止していたのでちかくの食べれるところをスタッフに尋ねたら面倒くさい感... | 4 | 3 | 4 | 4 | 3.0 | 4.0 | 4.0 | レジャー | 友達 | 45261 | 投稿者 | na | na |
| 8998 | B_ビジネス | 09_大阪 | 164935 | アートホテル大阪ベイタワー | 家族3人での利用でした。空庭温泉目的だったので、とても近くてよかった。ホテル下には、スーパー... | 3 | 2 | 5 | 3 | 3.0 | NaN | NaN | レジャー | 家族 | 45078 | NOBU2345 | 40代 | 女性 |
| 9689 | B_ビジネス | 10_福岡 | 182181 | ホテルオリエンタルエクスプレス福岡中洲川端 | 8月に2泊しましたが、使い捨てスリッパの袋が縦に破れていたり、トイレ・バスルームは下水臭く、... | 1 | 1 | 3 | 1 | 3.0 | 2.0 | NaN | レジャー | 家族 | 45139 | 投稿者 | na | na |
| 9704 | B_ビジネス | 10_福岡 | 12562 | ザ・レジデンシャルスイート・福岡 | 久しぶりにザ・レジデンシャルスィート福岡を利用しました。PayPayドームを利用する際に、私... | 4 | 4 | 5 | 5 | 4.0 | 3.0 | 3.0 | レジャー | 一人 | 45139 | ゆっきー2515 | 50代 | 男性 |
| 9838 | B_ビジネス | 10_福岡 | 180284 | The358 UMI | 孫が高校受験に合格した御祝の旅行宿泊でしたが、夕食のステーキ食べ放題を楽しみにしていたのに旅... | 3 | 3 | 3 | 4 | 3.0 | 3.0 | 1.0 | レジャー | 家族 | 45323 | ぱ.ん.だ | 50代 | 女性 |
for name, group in all_df.groupby('カテゴリー'):
print(name)
search_index = group['コメント'].str.contains('夕食') & group['コメント'].str.contains('残念')
print(group[search_index]['コメント'].values[:10]) # とりあえず10件のみ出力
print()
A_レジャー ['会席料理の宿を探していて見つけました。お料理大変おいしかったです。オールインクルーシブも気兼ねなくお酒を飲むことができて有り難かったです。少し残念だった点は、夕食の準備をして下さった方が急いでいたためか忙しなく、私の腕に手が当たって引っかかれてしまったり、お料理に火をつけたチャッカマンの先が家族の腕に当たって熱かったりしたことです。もう少しゆとりがあるといいと思いました。全体としては満足でした。機会があればまた利用したいです。ありがとうございました。' 'シンプルで静かで素敵なホテルでした。趣のある商店街の一角にあり、歩いてすぐのところにコンビニがあるのも便利でした。駐車場も無料で利用できました。和洋室は家族5人で泊っても十分な広さでしたし、部屋を出てすぐのところに喫煙所や自動販売機、電子レンジもあり便利でした。夕食がお弁当なのは少し残念でしたが部屋でゆっくり気兼ねなく食べれましたし、朝ごはんで選んだ鯛茶漬けはとても美味しく、バイキングの品数も丁度良い量でした。全体として、コスパは良いと思います。家族全員満足でした。' '2週間後の宿泊\u3000温泉地のホテルでなるべく価格を抑えて朝夕食事付き\u3000で探し、古いのかな、とおもい予約した。宿泊してよかったです。駐車場は直ぐ近く早めに着いたけど停められて\u3000観光、温泉街散策がゆっくりでき、お部屋もきれい。温泉は脱衣所から階段で降りて行くのに驚ましたが、とても気持ちよかったです。食事も美味しく補充の早さもよく特にホタテ美味しかったです。欲を言えば、朝牛乳が切れたのか無くなっていたのが残念です。' '愛犬と足の悪い姉と夫の3人と一匹で、伺いました。お部屋は、古い感じですが、和室で皆寛ぐ事が出来ました。ウェルカムドリンクも最高!夕食は、お部屋で愛犬を待たせることなく、楽しめましたし、姉も気を使わなくて良かった!と、喜んでいました。ただ、お風呂がとても寒く、お湯もぬるかったので…風邪を引きそうだったのが残念です。スタッフさんの、声がけもとても温かく、また伺いたいと思いました。' 'お食事は夕食朝食ともに、素晴らしかったです。お部屋とお風呂にブラシがなく?と思って帰りに気がついたのだが、フロントにアメニティがあり、到着時、一言欲しかったです。お布団が最初からひいてあり、和室にした意味合いが余り感じられず、残念でした。日帰り用の大広間は、怖い感じがしたので、改善したらもっと良くなると思います。フロント、売店周辺もやる気の無さが感じられました。お食事と温泉の質がとても良いので、又、利用したいと思いますました。' '家族三人での宿泊です。お風呂は期待通りゆっくり堪能でき、チェックイン前、チェックアウト後も利用して大満足でした。料理はバイキングでしたが、他ホテルと比べても上質で、とても美味しくいただけました。ただ、夕食、朝食時に開始時間前に並んだのですが、なかなか入れず、混雑の整理ができていない点や、ドリンクオーダーが来なかったり、統率・段取りの悪さが残念に思いました。また、今回仕方が無いこと思っていますが、大浴場までのエスカレータが水害で使用停止になっていたり、駐車場が道路を渡った先にあるなど、身体に一部不自由がある身としては残念に思いました。早く全面復旧されることを願っています。' '何回も泊まらせて頂いてますが、今回夕食のバイキング時80分までの時間制限があり時間近くなるとそろそろですと案内があったりと忙しなかった。泊まりでゆっくりしたいと期待していた分日常に戻ったかんじで残念でした。スタッフも人手不足が目立つ印象でした。ただ子ども達は大満足。子どもには良いけれど大人は物足りないかなぁ前は大人もゆっくりできて家族皆満足だったけど…せめてバイキングの時間制限はして欲しくない。' 'どうせ行くなら旅行割のある期間に行きたいなと思い、2023年1月31日に宿泊しました。ここのお宿のメインイベントは夕食のビュッフェで、蟹・いくら・ステーキなどが食べ放題というところでした。ビュッフェ会場が2ヶ所あり、簡単に言うとお値段の安い方と高い方でした。勿論、夕食がメインイベントとして宿泊したため、高い方のグリーンテラスという会場にてお食事をしました。一言でいうと大満足でした。ご飯の種類もたくさんあり、どれも美味しくて、お腹いっぱいでした。小さい子ども連れでしたが、ちゃんとベビーチェア(キッズチェア)もあり、またプレイルームもあり、ご飯を食べ終えて飽き飽きしていた娘はそこでものすごく楽しそうに遊んでいました。子どももいて時間もかかりましたが、2時間滞在してしまいました。またこのお宿は露天風呂が有名で、冬の時期の露天風呂は、顔が冷たいけど、お湯が温かく、何時間でも入っていられるような空間でした。気のせいか、次の日の化粧のノリが良かったように感じました。ベビーやキッズの館内着もあり良かったです。お部屋の壁が少し薄いのか、近くの部屋の扉の音などが響いてきていて、そこは残念だなと思いました。全体的には、とても満足して良い旅行になりました。また泊まりたいなとも思っています。' '8月後半に利用しました。洞爺湖には素敵なホテルが数々ある中で、迷って迷って選んだホテルです。決めては夕食がブッフェではない事。もちろん高い料金を出せば叶うのですが、こちらのホテルの料金はとてもリーゾナブルだと思います。広いお風呂の方が好きなので客室露天風呂付きではないグレードに部屋を選びましたが、2人には十分な広さでした。花火もお部屋から十分にを堪能することができましたし。個室での夕食も一品一品繊細でとても美味しかったです。ただクーラーが付いていなかったので、猛暑の今年は少し辛く扇風機を回してもらいました。そこだけが残念だったところです。翌朝の朝食会場からの眺めも素晴らしく、このホテルにして良かったと思えました。' '夕食は海鮮系の惣菜や蟹が食べられ、とても美味しかったです!!!子供向けのメニューがあまりなかった(ポテト、唐揚げはあり)のが少し残念でした。大浴場は男女交代制ですが、どちらにも滑り台がついており、子連れには嬉しいポイントでした!(滑り台はけっこう滑るので少し怖いかも、、、)子供用の館内着もあり嬉しかったですが、小さい方のサイズが全然なかったため2人いたのですが、1人分しか確保できなかったです。ですが、全体的には満足できるお宿でした!'] B_ビジネス ['夕食の北海御前4500円付のプランにしましたが、とても値段に見合わない質、量の食事でした。その分、レストランはガラガラでしたが。定食の方がリーズナブルなので、それを選べる形の方が嬉しかったです。部屋はツインにしていただけましたが、連泊の場合、2日に1回しか掃除が入らないというのが驚きでした。ニューオータニなのに。最近は人が足りないのでしょうが、他のホテルでは希望すれば掃除ありが普通なので残念でした。以前宿泊した時よりもレベルが落ちた気がします。フロントとかの対応はしっかりで良かったです。' '娘の結婚式に出席するために親族含めて2泊しました。式場にも近く夕食を摂るため近くに美味しいお店がありました。4部屋利用するため近い部屋してほしいと事前にホテルに電話したところ心よく引き受けていただきました。実際チェックインするとそのようにしていただきありがとうございました。お部屋もきれいで大浴場もきれいで良かったです。朝食はバイキング形式で北海道名物の味噌ラーメンやスープカレーがあり美味しかったです。連泊した2日間はほほ同じメニューだったので少し変えて欲しいなと思いました。スープカレーに入れるポテトと鳥のから揚げが冷たかったのが残念だったです。(温かいスープに入れるから冷たくてもいいのかもしれませんが)全体的に利用して良かったです。お世話になりました。' '良かった点駅前から乗車できるシャトルバスはとても便利でした、もう少し本数増やしてくれると観光の幅も広がるので嬉しいです。朝食はエッグステーションもありとても満足しました!種類も多く味も美味しかったです!夕食もずわい蟹があったり鹿のジンギスカンがあったり海鮮丼ができたり、デザートもシャトレーゼの店においてあるケーキがあったりととても満足しました。いまいちだった点プール、寒かったです人もまばらだし閑散としていて楽しくなかった。温泉は工事中で入れるところも少なく残念でした。500円の割引チケットは頂けました。外国人が多く、文化の違いなので仕方ありませんが片足あげて飲み食いされてる隣で食事とはなんとも、海外にいったら私も気をつけようと思いました。' '館内レストランで夕食を休止していたのでちかくの食べれるところをスタッフに尋ねたら面倒くさい感じで、場所も食事内容も書いてないチラシを渡され、離れたソファーで見てくれと。こんな扱いははじめての経験だった。他の事は満足だったので、残念。' '家族3人での利用でした。空庭温泉目的だったので、とても近くてよかった。ホテル下には、スーパー、ダイソー、パン屋、コンビニ、ファストフード等があり便利です。駅もすぐなので、町中へ出かけるのにも便利でした。夕食は、ホテル近くの居酒屋を期待してウロウロしたけど、思っていたより静かな駅前でした。迷うほど店はありません。ホテルで残念な点は、部屋はオシャレで小綺麗だけど、カーペット部分が誇りっぽい。エキストラベット下のカーペットは剥がれまくり。壁紙も剥がれていて少し不快でした。あと、テイクアウトのコーヒーが美味しくない。ジュースにすればよかった。。。' '8月に2泊しましたが、使い捨てスリッパの袋が縦に破れていたり、トイレ・バスルームは下水臭く、窓側の天井にはびっしり埃が付いていました。トイレのサニタリー袋にも汚れが付いていて、ここまで清掃がいい加減なホテルは初めてです。冷房の風の音も気になり、つけたまま寝ることができませんでした。その他、次の日の朝ご飯を冷蔵庫に入れて夕食に出かけると、電源がオフになったのか冷蔵庫の上部が熱くなっていて食べ物も温かくなっていました。こういったシステムのホテルもあるかと思いますが、なにか注意書でもあればなと思いました。宿泊費も結構高かったので、このクオリティは本当に残念です。' '久しぶりにザ・レジデンシャルスィート福岡を利用しました。PayPayドームを利用する際に、私は最高・最適なところと思っています。プロ野球の公式戦ホークス対イーグルスを観戦するために、午前中のうちに南九州の自宅を出発しました。あいにくの台風6号の接近により、大雨の中に九州自動車道を急ぎました。福岡県に入ったころで、PayPayドームでの公式戦中止のメールを受信しました。涙が出そうでした。しかし、ホテルの予約はあるので、宿泊は予定通り行いました。マリノアシティやMARK IS 福岡ももちでショッピングを楽しみました。夕食はPayPayドームで食べる予定だったのですが、試合中止と天候悪化でホテルに戻りました。ホテルの近くにあるボンパラスで夕食の惣菜を買いました。いろいろな惣菜が多彩にあり、にぎり寿司や刺身、麻婆豆腐などを買って、部屋で食べました。ホテルの部屋は一人で利用するには広すぎるぐらいで、快適でした。部屋にある洗濯機で洗濯をして、ホテル内のランドリーで乾燥もできました。台風が近づいている中でしたが、物音が気にならず、快適に眠りました。翌日は、福岡博物館でジブリ展を見に行こうとしましたが、台風のために開館が午後となり、残念でした。再度書きますが、ホテルは最高・最適でした。' '孫が高校受験に合格した御祝の旅行宿泊でしたが、夕食のステーキ食べ放題を楽しみにしていたのに旅行1ヶ月切った位にホテルから連絡が有り夕食の準備が出来ないので、今だったら無料でこちらからキャンセルしても良いとの事。そのまま宿泊だと夕食代返金、御部屋グレードアップ、ドリンクチケットと言われ今更別のホテルを探すのも大変なのでその条件で宿泊しました。フロントの対応は良く、部屋も広かったのですが、孫が楽しみにしていた夕食が無くなったので残念でした。折角の合格祝いだったのに少し残念でした。']
【演習】 外部変数を利用したエリアごとの作図¶
注意: 以下の演習は上のセルを全て実行してから続けて実施してください
2.1 【演習】 ワードクラウド (エリアごと)¶
# ToDo: 1.11.5 のセル中のコードをコピーして貼り付け,「カテゴリー」を「エリア」に変更する
for name, group in cross_150_df.groupby(level='エリア'):
print(name)
# 「カテゴリー」ごとに Jaccard 係数でソートする
sorted_columns = np.argsort(jaccard_attrs_df.loc[name].values)[::-1][:75]
# Jaccard 係数Top 75語をソートして抽出する
group_cross_df = group.iloc[:,sorted_columns]
# プロットする
gssm_utils.plot_wordcloud(" ".join(group_cross_df.columns))
01_登別
02_草津
03_箱根
04_道後
05_湯布院
06_札幌
07_名古屋
08_東京
09_大阪
10_福岡
2.2 【演習】 共起ネットワーク図 (エリアごと)¶
# ToDo: 1.11.6 のセル中のコードをコピーして貼り付け,「カテゴリー」を「エリア」に変更する
# 必要ライブラリのインポート
from scipy.sparse import csc_matrix
for name, group in cross_150_df.groupby(level='エリア'):
print(name)
# 「カテゴリー」ごとに Jaccard 係数でソートする
sorted_columns = np.argsort(jaccard_attrs_df.loc[name].values)[::-1][:75]
# Jaccard 係数Top 75語をソートして抽出する
group_cross_df = group.iloc[:,sorted_columns]
# 共起行列を作成する
X = group_cross_df.values
X = csc_matrix(X)
Xc = (X.T * X)
Xc = np.triu(Xc.toarray())
# 共起行列を DataFrame に整える
group_cooccur_df = pd.DataFrame(Xc, columns=group_cross_df.columns, index=group_cross_df.columns)
# 共起行列の中身を Jaccard 係数に入れ替える
group_jaccard_df = gssm_utils.jaccard_coef(group_cooccur_df, group_cross_df)
# 抽出語の出現回数を取得する
word_counts = group.sum(axis=0).values
# プロットする
gssm_utils.plot_cooccur_network(group_jaccard_df, word_counts, np.sort(group_jaccard_df.values.reshape(-1))[::-1][60])
01_登別
<Figure size 800x800 with 0 Axes>
02_草津
<Figure size 800x800 with 0 Axes>
03_箱根
<Figure size 800x800 with 0 Axes>
04_道後
<Figure size 800x800 with 0 Axes>
05_湯布院
<Figure size 800x800 with 0 Axes>
06_札幌
<Figure size 800x800 with 0 Axes>
07_名古屋
<Figure size 800x800 with 0 Axes>
08_東京
<Figure size 800x800 with 0 Axes>
09_大阪
<Figure size 800x800 with 0 Axes>
10_福岡
<Figure size 800x800 with 0 Axes>
2.3 【演習】 トピック分布 (エリアごと)¶
# ToDo: 1.11.7.2 のセル中のコードをコピーして貼り付け,そのまま実行する
n_top_words = 75
gssm_utils.plot_topic_model(lda, feature_names, n_top_words)
# ToDo: 1.11.7.3 のセル中のコードをコピーして貼り付け,「カテゴリー」を「エリア」に変更する
for name, group in cross_150_df.groupby(level='エリア'):
print(name)
# 文書ごとのトピック比率を取得
doc_topic_distributions = lda.transform(group.values)
# 文書全体のトピック比率を計算(平均を取る)
overall_topic_distribution = np.mean(doc_topic_distributions, axis=0)
gssm_utils.plot_topic_distribution(overall_topic_distribution)
01_登別
02_草津
03_箱根
04_道後
05_湯布院
06_札幌
07_名古屋
08_東京
09_大阪
10_福岡
2.4 【演習】 本文の参照 (エリアごと)¶
# ToDo: 1.11.8 のセル中のコードをコピーして貼り付け,「カテゴリー」を「エリア」に変更する
for name, group in all_df.groupby('エリア'):
print(name)
search_index = group['コメント'].str.contains('夕食') & group['コメント'].str.contains('残念')
display(group[search_index].head()) # 先頭の5件ずつ表示
01_登別
| カテゴリー | エリア | 施設番号 | 施設名 | コメント | 総合 | サービス | 立地 | 部屋 | 設備・アメニティ | 風呂 | 食事 | 旅行の目的 | 同伴者 | 宿泊年月 | 投稿者 | 年代 | 性別 | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 70 | A_レジャー | 01_登別 | 29995 | ゆとりろ洞爺湖 | 会席料理の宿を探していて見つけました。お料理大変おいしかったです。オールインクルーシブも気兼... | 4 | 3 | 4 | 5 | 4.0 | 4.0 | 4.0 | レジャー | 家族 | 45139 | 投稿者 | na | na |
| 155 | A_レジャー | 01_登別 | 5499 | 室蘭プリンスホテル | シンプルで静かで素敵なホテルでした。趣のある商店街の一角にあり、歩いてすぐのところにコンビニ... | 4 | 4 | 5 | 4 | 4.0 | NaN | 3.0 | レジャー | 家族 | 45200 | Rikappa☆ | 40代 | 女性 |
| 166 | A_レジャー | 01_登別 | 37379 | 登別温泉 名湯の宿 パークホテル雅亭 | 2週間後の宿泊 温泉地のホテルでなるべく価格を抑えて朝夕食事付き で探し、古いのかな、とおも... | 5 | 5 | 5 | 5 | 5.0 | 5.0 | 5.0 | レジャー | 家族 | 45200 | にゃんこのら | 50代 | 女性 |
| 218 | A_レジャー | 01_登別 | 29995 | ゆとりろ洞爺湖 | 愛犬と足の悪い姉と夫の3人と一匹で、伺いました。お部屋は、古い感じですが、和室で皆寛ぐ事が出... | 4 | 5 | 3 | 3 | 3.0 | 2.0 | 5.0 | レジャー | 家族 | 45231 | 投稿者 | na | na |
| 244 | A_レジャー | 01_登別 | 162792 | 虎杖浜温泉ホテル | お食事は夕食朝食ともに、素晴らしかったです。お部屋とお風呂にブラシがなく?と思って帰りに気が... | 4 | 4 | 4 | 2 | 3.0 | 3.0 | 5.0 | レジャー | 家族 | 44986 | 投稿者 | na | na |
02_草津
| カテゴリー | エリア | 施設番号 | 施設名 | コメント | 総合 | サービス | 立地 | 部屋 | 設備・アメニティ | 風呂 | 食事 | 旅行の目的 | 同伴者 | 宿泊年月 | 投稿者 | 年代 | 性別 | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 1019 | A_レジャー | 02_草津 | 172893 | リブマックスリゾート草津温泉 | 6/14に宿泊しました。あいにく雨でした。少し早めにチェックインさせていただきありがとうござ... | 4 | 4 | 3 | 4 | 5.0 | 3.0 | 4.0 | レジャー | 家族 | 45078 | 投稿者 | na | na |
| 1028 | A_レジャー | 02_草津 | 179990 | ラビスタ草津ヒルズ(共立リゾート) | 全てに大満足でした。大浴場も貸し切り露天風呂も気持ちよく使えました。温泉から上がった後の飲み... | 5 | 5 | 5 | 5 | 5.0 | 5.0 | 5.0 | レジャー | 家族 | 45108 | 投稿者 | na | na |
| 1029 | A_レジャー | 02_草津 | 5270 | 草津温泉 ホテルヴィレッジ | 良かったことリゾートパスポートでたくさん遊べた。1泊では遊びきれないほど。アーチェリーのスタ... | 4 | 4 | 3 | 2 | 3.0 | 5.0 | 4.0 | レジャー | 家族 | 45383 | 投稿者 | na | na |
| 1030 | A_レジャー | 02_草津 | 17837 | 草津温泉 喜びの宿 高松 | 全国旅行支援は利用せずに家族旅行での利用。受付スタッフや館内や送迎スタッフの対応は親切で良か... | 2 | 4 | 4 | 1 | 1.0 | 4.0 | 4.0 | レジャー | 家族 | 45017 | Lefua82 | 40代 | 女性 |
| 1071 | A_レジャー | 02_草津 | 56137 | 草津温泉 ホテル櫻井 | 何度か目の宿泊で、数年ぶりでしたが大変残念な機会となりました到着車の誘導やチェックインはいつ... | 2 | 2 | 3 | 3 | 3.0 | 4.0 | 1.0 | レジャー | 家族 | 45231 | めい幸 | 50代 | 女性 |
03_箱根
| カテゴリー | エリア | 施設番号 | 施設名 | コメント | 総合 | サービス | 立地 | 部屋 | 設備・アメニティ | 風呂 | 食事 | 旅行の目的 | 同伴者 | 宿泊年月 | 投稿者 | 年代 | 性別 | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 2025 | A_レジャー | 03_箱根 | 19786 | 箱根湯本温泉 ホテルマイユクール祥月 | 4月22日に結婚記念日45周年で1泊致しました。以前、改装前に1泊したことが有ります。今回は... | 4 | 4 | 5 | 5 | 5.0 | 4.0 | 4.0 | レジャー | 家族 | 45383 | 千春大好き7034 | 60代 | 女性 |
| 2028 | A_レジャー | 03_箱根 | 15250 | EN RESORT Re’Cove Hakone(旧:リ・カーヴ箱根) | 11月の土日に宿泊しました。夕食のバイキングが美味しかったです。北館に泊まりましたが、レスト... | 3 | 4 | 5 | 2 | 4.0 | 5.0 | 5.0 | レジャー | 家族 | 45231 | 投稿者 | na | na |
| 2040 | A_レジャー | 03_箱根 | 142546 | 四季を愉しむ貸切温泉 ゆとりろ庵 | スタッフの皆さんはとても優しく丁寧に接してくれました。チェックインの時も、端末操作に戸惑って... | 5 | 5 | 5 | 5 | 5.0 | 5.0 | 5.0 | レジャー | 家族 | 45383 | 拡散型ミラマクス | 40代 | 男性 |
| 2066 | A_レジャー | 03_箱根 | 142546 | 四季を愉しむ貸切温泉 ゆとりろ庵 | お世話になりました。古い宿ですが雰囲気が良かったです。フロントや、飲み物サービスなどは大満足... | 3 | 3 | 5 | 4 | 4.0 | 3.0 | 2.0 | レジャー | 友達 | 45078 | テトテトしゃん | 70代 | 女性 |
| 2075 | A_レジャー | 03_箱根 | 5081 | 箱根湯本温泉 ホテルおくゆもと | 子連れ妊娠中の宿泊でしたが、接客も良く比較的満足でした。お料理も美味しかったですが、夕食の子... | 5 | 5 | 5 | 3 | 5.0 | 4.0 | 4.0 | レジャー | 家族 | 45108 | 投稿者 | na | na |
04_道後
| カテゴリー | エリア | 施設番号 | 施設名 | コメント | 総合 | サービス | 立地 | 部屋 | 設備・アメニティ | 風呂 | 食事 | 旅行の目的 | 同伴者 | 宿泊年月 | 投稿者 | 年代 | 性別 | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 3157 | A_レジャー | 04_道後 | 8384 | 道後プリンスホテル〜旬華趣湯 あったらいいな、が湧く湯宿〜 | 夕食の際の細やかな説明がなく、どのタイミングで次の食事なのか子供のたこ焼きはいつ出来るのか?... | 4 | 4 | 4 | 3 | 3.0 | 3.0 | 2.0 | レジャー | 家族 | 44986 | 投稿者 | na | na |
| 3266 | A_レジャー | 04_道後 | 13653 | 道後温泉 ホテル椿館 | 道後温泉本館や商店街から近い立地なので、とても便利でした。ホテルの温泉も良かったです。接客も... | 5 | 4 | 5 | 4 | 3.0 | 4.0 | 4.0 | レジャー | 一人 | 45352 | ( ^o^ )4649 | 30代 | 女性 |
| 3420 | A_レジャー | 04_道後 | 11332 | 道後温泉 ふなや | 女性二人の旅行でしたので宿ではのんびりと過ごしたいと思い部屋での夕食と温泉つきのプランを選び... | 4 | 4 | 5 | 4 | 5.0 | 4.0 | 5.0 | レジャー | 一人 | 44927 | 投稿者 | na | na |
| 3527 | A_レジャー | 04_道後 | 10788 | 道後温泉 道後舘 | 立地はハイカラ通りから近いですが少し高台にあり坂道になっています。到着時たくさんのスタッフに... | 5 | 5 | 4 | 5 | 5.0 | 5.0 | 4.0 | レジャー | 家族 | 45139 | ひろみEX | 50代 | 女性 |
| 3643 | A_レジャー | 04_道後 | 141611 | オーベルジュ道後 | からくり時計からほど近く、道後を観光するなら最適な場所だと思います。部屋も広くて快適でした。... | 3 | 3 | 5 | 4 | 3.0 | 2.0 | 2.0 | レジャー | 家族 | 45261 | 投稿者 | na | na |
05_湯布院
| カテゴリー | エリア | 施設番号 | 施設名 | コメント | 総合 | サービス | 立地 | 部屋 | 設備・アメニティ | 風呂 | 食事 | 旅行の目的 | 同伴者 | 宿泊年月 | 投稿者 | 年代 | 性別 | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 4024 | A_レジャー | 05_湯布院 | 76377 | 由布院温泉 朝霧のみえる宿 ゆふいん花由 | 食事が大変美味しかったです。夕食も手が込んでおり、器も素敵で大変美味しかったです。また、旅館... | 5 | 5 | 4 | 4 | 5.0 | 4.0 | 5.0 | レジャー | 家族 | 44986 | 栗納豆 | 40代 | 女性 |
| 4041 | A_レジャー | 05_湯布院 | 129936 | 旅籠Hatago 香乃蔵 (旧名:湯亭 香乃蔵) | お食事が素晴らしいお宿。出てくる一品一品が美味しく大満足です!器も、温かい物は温めてあり冷た... | 5 | 5 | 3 | 5 | 5.0 | 4.0 | 5.0 | レジャー | 家族 | 45017 | thinking time | 40代 | 女性 |
| 4092 | A_レジャー | 05_湯布院 | 31932 | 湯平温泉 花合野 | 綜合評価は2にしましたが、心情的には1です。なぜなら最低限のサービスを提供していないので、評... | 2 | 1 | 3 | 3 | 2.0 | 1.0 | 4.0 | レジャー | 家族 | 45231 | 投稿者 | na | na |
| 4109 | A_レジャー | 05_湯布院 | 76377 | 由布院温泉 朝霧のみえる宿 ゆふいん花由 | この宿はお天気次第で評価はかなり変わると思います。 お天気がよければ素晴らしい眺めなのでしょ... | 4 | 3 | 4 | 4 | 3.0 | 4.0 | 4.0 | レジャー | 家族 | 45383 | バルおばさん | 60代 | 女性 |
| 4147 | A_レジャー | 05_湯布院 | 106080 | 湯布院温泉 御宿 由布乃庄 | 到着がやや遅くなってしまったところ、夕食の時間を規定よりもずらして頂き、食事前にお風呂に入り... | 5 | 5 | 4 | 5 | 4.0 | 5.0 | 5.0 | レジャー | 家族 | 44958 | 投稿者 | na | na |
06_札幌
| カテゴリー | エリア | 施設番号 | 施設名 | コメント | 総合 | サービス | 立地 | 部屋 | 設備・アメニティ | 風呂 | 食事 | 旅行の目的 | 同伴者 | 宿泊年月 | 投稿者 | 年代 | 性別 | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 5570 | B_ビジネス | 06_札幌 | 163 | ニューオータニイン札幌 | 夕食の北海御前4500円付のプランにしましたが、とても値段に見合わない質、量の食事でした。そ... | 3 | 4 | 4 | 4 | 3.0 | 3.0 | 3.0 | ビジネス | 仕事仲間 | 45231 | 投稿者 | na | na |
| 5838 | B_ビジネス | 06_札幌 | 183892 | ダイワロイネットホテル札幌中島公園 | 娘の結婚式に出席するために親族含めて2泊しました。式場にも近く夕食を摂るため近くに美味しいお... | 4 | 5 | 5 | 5 | 5.0 | 5.0 | 3.0 | レジャー | 家族 | 45170 | ひきはち | 50代 | 女性 |
| 5972 | B_ビジネス | 06_札幌 | 17678 | シャトレーゼ ガトーキングダムサッポロ ホテル&スパリゾート | 良かった点駅前から乗車できるシャトルバスはとても便利でした、もう少し本数増やしてくれると観光... | 4 | 3 | 4 | 4 | 2.0 | 2.0 | 5.0 | レジャー | 家族 | 45323 | nanatama_go | 50代 | 男性 |
07_名古屋
| カテゴリー | エリア | 施設番号 | 施設名 | コメント | 総合 | サービス | 立地 | 部屋 | 設備・アメニティ | 風呂 | 食事 | 旅行の目的 | 同伴者 | 宿泊年月 | 投稿者 | 年代 | 性別 | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 6417 | B_ビジネス | 07_名古屋 | 10897 | ホテル メルパルク名古屋 | 館内レストランで夕食を休止していたのでちかくの食べれるところをスタッフに尋ねたら面倒くさい感... | 4 | 3 | 4 | 4 | 3.0 | 4.0 | 4.0 | レジャー | 友達 | 45261 | 投稿者 | na | na |
08_東京
| カテゴリー | エリア | 施設番号 | 施設名 | コメント | 総合 | サービス | 立地 | 部屋 | 設備・アメニティ | 風呂 | 食事 | 旅行の目的 | 同伴者 | 宿泊年月 | 投稿者 | 年代 | 性別 |
|---|
09_大阪
| カテゴリー | エリア | 施設番号 | 施設名 | コメント | 総合 | サービス | 立地 | 部屋 | 設備・アメニティ | 風呂 | 食事 | 旅行の目的 | 同伴者 | 宿泊年月 | 投稿者 | 年代 | 性別 | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 8998 | B_ビジネス | 09_大阪 | 164935 | アートホテル大阪ベイタワー | 家族3人での利用でした。空庭温泉目的だったので、とても近くてよかった。ホテル下には、スーパー... | 3 | 2 | 5 | 3 | 3.0 | NaN | NaN | レジャー | 家族 | 45078 | NOBU2345 | 40代 | 女性 |
10_福岡
| カテゴリー | エリア | 施設番号 | 施設名 | コメント | 総合 | サービス | 立地 | 部屋 | 設備・アメニティ | 風呂 | 食事 | 旅行の目的 | 同伴者 | 宿泊年月 | 投稿者 | 年代 | 性別 | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 9689 | B_ビジネス | 10_福岡 | 182181 | ホテルオリエンタルエクスプレス福岡中洲川端 | 8月に2泊しましたが、使い捨てスリッパの袋が縦に破れていたり、トイレ・バスルームは下水臭く、... | 1 | 1 | 3 | 1 | 3.0 | 2.0 | NaN | レジャー | 家族 | 45139 | 投稿者 | na | na |
| 9704 | B_ビジネス | 10_福岡 | 12562 | ザ・レジデンシャルスイート・福岡 | 久しぶりにザ・レジデンシャルスィート福岡を利用しました。PayPayドームを利用する際に、私... | 4 | 4 | 5 | 5 | 4.0 | 3.0 | 3.0 | レジャー | 一人 | 45139 | ゆっきー2515 | 50代 | 男性 |
| 9838 | B_ビジネス | 10_福岡 | 180284 | The358 UMI | 孫が高校受験に合格した御祝の旅行宿泊でしたが、夕食のステーキ食べ放題を楽しみにしていたのに旅... | 3 | 3 | 3 | 4 | 3.0 | 3.0 | 1.0 | レジャー | 家族 | 45323 | ぱ.ん.だ | 50代 | 女性 |